package com.banggood.upms.web;

import com.banggood.silk.web.api.exception.SkbException;
import com.banggood.upms.bean.exception.ExceptionEnum;
import com.banggood.upms.bean.po.Tree;
import com.banggood.upms.bean.po.User;
import com.banggood.upms.bean.po.UserTree;
import com.banggood.upms.bean.vo.UserTreeVo;
import com.banggood.upms.bean.vo.validation.AdjustGroup;
import com.banggood.upms.bean.vo.validation.SearchGroup;
import com.banggood.upms.common.constant.UpmsConstant;
import com.banggood.upms.service.TreeService;
import com.banggood.upms.service.UserService;
import com.banggood.upms.service.UserTreeService;
import com.banggood.upms.converter.UserTreeConverter;
import io.swagger.annotations.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author XuChuangFeng
 */
@RequestMapping("/user-tree")
@RestController
@Api(value = "用户跟树", description = "为用户分配树节点，查看这个用户已分配的树节点。")
public class UserTreeController {

    protected final Log logger = LogFactory.getLog(getClass());
    @Autowired
    private UserTreeService userTreeService;
    @Autowired
    private UserService userService;
    @Autowired
    private TreeService treeService;
    @Autowired
    private UserTreeConverter userTreeConverter;

    /**
     * @param vo
     * @return 用户在该树结构的分配状况，比如用户所属的部门集合，用户角色集合
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    @ApiOperation(value = "用户与树节点映射关系搜索", notes = "根据userId跟树类型，搜索用户与树的映射关系。", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户的主键", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "treeType", value = "树类型", required = true, paramType = "query", dataType = "String"),
    })
    public List<UserTree> selectUserTrees(@Validated({SearchGroup.class}) UserTreeVo vo) {
        List<UserTree> userTrees = userTreeService.selectByUserIdAndTreeType(vo);
        return userTrees;
    }

    /**
     * 用户跟树的分配映射（树包括角色跟部门）
     *
     * @param vo
     * @return
     */
    @RequestMapping(value = "/adjust", method = RequestMethod.POST)
    @ApiOperation(value = "用户与树节点的映射分配", notes = "为用户分配树节点映射，比如分配角色，分配部门，分配岗位", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户的主键", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "newTreeIds", value = "新的树列表，以逗号隔开，旧的会被覆盖", required = false, paramType = "query", dataType = "Array"),
            @ApiImplicitParam(name = "treeType", value = "树类型", required = true, paramType = "query", dataType = "String"),
    })
    @ApiResponses({
            @ApiResponse(code = 2003, message = "必须指定树类型节点分配!"),
            @ApiResponse(code = 1009, message = "用户不存在!")
    })
    public String adjustTree(@Validated({AdjustGroup.class}) UserTreeVo vo) throws Exception {
        // 需要传入系统ID，否则其他系统的数据将会被删除
        if(vo.getTreeType() == null) {
            throw new SkbException(ExceptionEnum.TREE_TYPE_CANT_BE_NULL.getCode(), ExceptionEnum.TREE_TYPE_CANT_BE_NULL.getMessage());
        }
        User user = userService.selectByPrimaryKey(vo.getUserId());
        if(user == null) {
            throw new SkbException(ExceptionEnum.USER_NOT_EXISTS.getCode(), ExceptionEnum.USER_NOT_EXISTS.getMessage());
        }
        /**
         * #1, 查看之前是否为这个树节点分配过权限，如果没有就直接将此次添加的全部新增，返回
         * #2, 分配过权限的话，要做比较，分配前A跟分配后B的集合的并集C不做任何操作，C在A中的绝对补集做删除操作，C在B中的绝对补集做新增操作。
         * #3, 逻辑跟用户分配树一样
         */
        logger.debug("本次操作的树节点主键：" + vo.getUserId());
        String brief = null;
        // 前端没有传入任何的分配ID，newTreeIds是空，直接删除所有已分配的
        if (CollectionUtils.isEmpty(vo.getNewTreeIds())) {
            brief = userTreeService.deleteAll(vo);
        } else {
            // #1
            List<UserTree> preAdjustUserTrees = userTreeService.selectByUserIdAndTreeType(vo);
            if (CollectionUtils.isEmpty(preAdjustUserTrees)) {
                brief = userTreeService.insertUserTrees(userTreeConverter.transferToPersistentList(vo));
            } else {
                // #2
                List<String> idsForRemove = new ArrayList<>();
                List<UserTree> objForInsert = new ArrayList<>();
                // 初始化待删除列表跟带添加列表
                userTreeConverter.prepareAdjustElements(vo, preAdjustUserTrees, idsForRemove, objForInsert);
                brief = userTreeService.adjustUserTrees(vo.getTreeType(), vo.getUserId(), objForInsert, idsForRemove);
            }
        }
        return brief;
    }

    @GetMapping("/search-users")
    @ApiOperation(value = "查询用户", notes = "根据传入的树节点ID，查询分配了此节点的未被删除的用户", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "树节点id", required = true, paramType = "query", dataType = "String"),
    })
    public List<User> searchUsersByTreeId(@RequestParam String id) throws Exception {
        return userTreeService.selectUsersByTreeId(id);
    }

    @GetMapping("/sync-path")
    @ApiOperation(value = "同步path路径", notes = "根据树节点的path，同步用户与树中间表的path", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pwd", value = "操作密钥", required = true, paramType = "query", dataType = "String"),
    })
    @ApiIgnore
    public void syncAllUserTreePath(@RequestParam String pwd) throws Exception {
        if(!UpmsConstant.SUCCESS.equals(pwd)) {
            throw new SkbException();
        }
        List<Tree> trees = treeService.selectAll();
        Map<String, Tree> treeMap = new HashMap<>();
        for(Tree tree : trees) {
            treeMap.put(tree.getTreeId(), tree);
        }
        List<UserTree> userTrees = userTreeService.selectAll();
        for(UserTree userTree : userTrees) {
           userTree.setPath(treeMap.get(userTree.getTreeId()).getPath());
           userTreeService.updateByPrimaryKey(userTree);
        }
    }

    @GetMapping("/verify-path")
    @ApiOperation(value = "校验path字段", notes = "校验树表的path是否合法，返回不合法的树节点id", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pwd", value = "操作密钥", required = true, paramType = "query", dataType = "String"),
    })
    @ApiIgnore
    public String verifyTreePath(@RequestParam String pwd) throws Exception {
        if(!UpmsConstant.SUCCESS.equals(pwd)) {
            throw new SkbException();
        }
        List<Tree> trees = treeService.selectAll();

        Map<String, Tree> treeMap = new HashMap<>();
        for(Tree tree : trees) {
            treeMap.put(tree.getTreeId(), tree);
        }

        StringBuffer buffer = new StringBuffer();
        for(Tree tree : trees) {
            if(StringUtils.isEmpty(tree.getParentId())) {
                if(!tree.getPath().equalsIgnoreCase(UpmsConstant.SLASH + tree.getNodeCode())) {
                    buffer.append(tree.getTreeId() + ",");
                }
            } else {
                if(!tree.getPath().equalsIgnoreCase(treeMap.get(tree.getParentId()).getPath() + UpmsConstant.SLASH + tree.getNodeCode())) {
                    buffer.append(tree.getTreeId() + ",");
                }
            }
        }
        return buffer.toString();
    }
}
